﻿using Com.Lancetinc.Evs.Helpers;
using System;
using System.Collections.Generic;
using System.Text;

namespace Com.Lancetinc.Evs.Cameras
{
    public static class CameraLib
    {
        public static void InitializeProps(int deviceIndex, IEnumerable<CameraProp> props)
        {
            foreach (CameraProp prop in props)
            {
                LoadProp(deviceIndex, prop);
            }
        }

        public static string GetDeviceName(int deviceIndex)
        {
            StringBuilder sb = new StringBuilder(300);
            HCameraLib.hGetVideoDeviceFriendlyName(deviceIndex, sb, 256);
            return sb.ToString();
        }

        public static int FindVideoDeviceIndex(string typeCode)
        {
            var deviceCount = HCameraLib.hEnumVideoDevice();
            if (deviceCount == -1)
            {
                // 获取视频设备失败
                throw new ApplicationException(I18nHelper.Default.GetMessage("FailedToEnumVideoDevice"));
            }
            if (deviceCount == 0)
            {
                // 没有找到视频设备
                throw new ApplicationException(I18nHelper.Default.GetMessage("CannotNotFoundVideoDevice"));
            }

            var videoConfig = AppConfigHelper.GetVideoConfig(typeCode);
            if (videoConfig == null)
            {
                throw new ApplicationException(I18nHelper.Default.GetMessage("CannotFoundPidVidByTypeCode"));
            }
            int configPid = videoConfig.Pid;
            int configVid = videoConfig.Vid;

            int vid = 0;
            int pid = 0;
            for (int i = 0; i < deviceCount; i++)
            {
                HCameraLib.hGetVideoDeviceVIDPID(i, ref vid, ref pid);
                if (vid == configVid && pid == configPid)
                {
                    return i;
                }
            }
            throw new ApplicationException(I18nHelper.Default.GetMessageWithArgs("CannotNotFoundVideoDeviceWithPidVid", configPid, configVid));
        }

        public static CameraInfo[] EnumVideoDevice()
        {
            var deviceCount = HCameraLib.hEnumVideoDevice();
            if (deviceCount <= 0)
            {
                return Array.Empty<CameraInfo>();
            }

            var cameras = new List<CameraInfo>();
            var szFriendlyName = new StringBuilder(300);
            int vid = 0;
            int pid = 0;
            for (int i = 0; i < deviceCount; i++)
            {
                HCameraLib.hGetVideoDeviceFriendlyName(i, szFriendlyName, 256);
                var name = szFriendlyName.ToString();
                HCameraLib.hGetVideoDeviceVIDPID(i, ref vid, ref pid);
                if (vid <= 0 || pid <= 0)
                    continue;

                cameras.Add(new CameraInfo(name, vid, pid));
            }
            return cameras.ToArray();
        }
        
        public static void LoadProp(int deviceIndex, CameraProp prop)
        {
            int pid = (int)prop.PropId;
            int modifyFlag = 0;
            int autoFlag = 0;

            if (prop.Category == CameraPropCategory.ProcAmp)
            {
                HCameraLib.hGetVideoProcAmpInfo(deviceIndex, (int)prop.PropId,
                    ref prop.Min, ref prop.Max, ref prop.Step, ref prop.DefaultValue, ref modifyFlag);
                prop.ModifyFlag = (CameraPropModifyFlag)modifyFlag;

                HCameraLib.hGetVideoProcAmpValue(deviceIndex, pid, ref prop.Value, ref autoFlag);
                prop.AutoFlag = (CameraPropAutoFlag)autoFlag;
            }
            else if (prop.Category == CameraPropCategory.Control)
            {
                HCameraLib.hGetVideoCameraControlInfo(deviceIndex, (int)prop.PropId,
                    ref prop.Min, ref prop.Max, ref prop.Step, ref prop.DefaultValue, ref modifyFlag);
                prop.ModifyFlag = (CameraPropModifyFlag)modifyFlag;

                HCameraLib.hGetVideoCameraControlValue(deviceIndex, pid, ref prop.Value, ref autoFlag);
                prop.AutoFlag = (CameraPropAutoFlag)autoFlag;
            }
            else
            {
                throw new ApplicationException("Not support: " + prop.ToString());
            }
        }

        public static void LoadPropValue(int deviceIndex, CameraProp prop)
        {
            int pid = (int)prop.PropId;
            int autoFlag = 0;

            if (prop.Category == CameraPropCategory.ProcAmp)
            {
                HCameraLib.hGetVideoProcAmpValue(deviceIndex, pid, ref prop.Value, ref autoFlag);
                prop.AutoFlag = (CameraPropAutoFlag)autoFlag;
            }
            else if (prop.Category == CameraPropCategory.Control)
            {
                HCameraLib.hGetVideoCameraControlValue(deviceIndex, pid, ref prop.Value, ref autoFlag);
                prop.AutoFlag = (CameraPropAutoFlag)autoFlag;
            }
            else
            {
                throw new ApplicationException("Not support: " + prop.ToString());
            }
        }

        public static void SaveProp(int deviceIndex, CameraProp prop)
        {
            int pid = (int)prop.PropId;
            int propFlag = (int)prop.AutoFlag;
            if (prop.Category == CameraPropCategory.ProcAmp)
            {
                HCameraLib.hSetVideoProcAmpValue(deviceIndex, pid, prop.Value, propFlag);
            }
            else if (prop.Category == CameraPropCategory.Control)
            {
                HCameraLib.hSetVideoCameraControlValue(deviceIndex, pid, prop.Value, propFlag);
            }
            else
            {
                throw new ApplicationException("Not support: " + prop.ToString());
            }
        }
    }

    public class CameraInfo
    {
        public CameraInfo(string name, int vid, int pid)
        {
            Name = name;
            Vid = vid;
            Pid = pid;
        }

        public string Name { get; }
        public int Vid { get; }
        public int Pid { get; }
    }
}
